#include "application.h"
#include "main.h"
#include "stm32l1xx_hal.h"
#include "dma.h"
#include "tim.h"
#include "usart.h"
#include "gpio.h"

#include "bsp.h"
#include "config.h"
#include "led.h"
#include "common_api.h"
#include "air530.h"
#include "in_out.h"
#include "fingerprint.h"
#include "tfp825r6l.h"
#include "application.h"
#include "mqtt.h"
#include "air720.h"
#include "network.h"
#include "jansson.h"
#include "aliyun_model.h"
#include "aliyun_utils.h"
#include "eeprom.h"

SYSTEM_STRU sys;
APP_FLAG app_flags;

void LED1_State(void);
void * ExtractVal(char * str, int num, char * type);

void APP_SysInit(void)
{
	u8 ret = APP_IsFirstUpload();
	if(ret)
	{
		sys.hold_time  = CFG_HOLD_TIME;
	}else
	{
		FLASHEx_EEPROM_READ(0,(u8 *)&sys.info,sizeof(APP_INFO));
		sys.hold_time = sys.info.hold_time;
	}
}

void APP_Init(void)
{
	while(HAL_GPIO_ReadPin(PWR_ON_GPIO_Port,PWR_ON_Pin) == 0)
	{
		printf("没有打开电源键，程序无法启动 \r\n");
		HAL_Delay(1000);
	}
	INOUT_Init();
	DELAY_Init(32);
	
//	HAL_TIM_Base_Start_IT(&htim2);
//	HAL_TIM_Base_Start_IT(&htim7);
//	HAL_TIM_Base_Start_IT (&htim4);
//	__HAL_TIM_DISABLE(&htim4);
	
	//@ 开启空闲中断
//	__HAL_UART_ENABLE_IT(&huart1, UART_IT_IDLE);
	//@ 开启串口 DMA 接收
//	HAL_UART_Receive_DMA(&huart1, u1Receiver.buffer, U1_RXBUF_SIZE);
//	__HAL_UART_ENABLE_IT(&huart1, UART_IT_RXNE);
	
	
	__HAL_UART_ENABLE_IT(&huart2, UART_IT_RXNE);
	//	//@ 开启空闲中断
	//	__HAL_UART_ENABLE_IT(&huart2, UART_IT_IDLE);
	//	//@ 开启串口 DMA 接收
	//	HAL_UART_Receive_DMA(&huart2, u2Receiver.buffer,U2_RXBUF_SIZE);
	//@ 开启空闲中断
	__HAL_UART_ENABLE_IT(&huart3, UART_IT_IDLE);
	//@ 开启串口 DMA 接收
	HAL_UART_Receive_DMA(&huart3, u3Receiver.buffer, U3_RXBUF_SIZE);
	delay_ms(500);	//@ 上电延时
	//@ 初始化接收,发送,命令数据的 缓冲区 以及各状态参数
	
	TFP_Init();
	
	APP_SysInit();
	AIR720_OPEN_PWR();
	AliIoT_Parameter_Init();
}

u8 APP_IsFirstUpload(void)
{
	APP_INFO * info = &sys.info;
	FLASHEx_EEPROM_READ(0,(u8 *)info,sizeof(APP_INFO));
	
	if(info->first_upload_f != FIRST_UPLOAD_FLAG)
	{
		printf("系统第 1 次上电 \r\n");
		info->first_upload_f = FIRST_UPLOAD_FLAG;
		info->hold_time = CFG_HOLD_TIME;
		FLASHEx_EEPROM_WRITE(0,(u8 *)info,sizeof(APP_INFO));
		return 1;
	}
	return 0;
}


void APP_InputChenalAction_Process(void)
{
	char json_str[128];
//	if (input_hold.ch3)
//	{ 
//		static u8 state = 0;
//		state = !state;
//		sprintf(json_str,"{\"params\": {\"%s\": %u}}",STRI(DIN3_NAME),state);
//		MQTT_PublishQs0(P_TOPIC_NAME, json_str, strlen(json_str));
//		input_hold.ch3 = 0;
//	}
//	if (input_hold.ch4)
//	{
//		static u8 state = 0;
//		state = !state;
//		sprintf(json_str,"{\"params\": {\"%s\": %u}}",STRI(DIN4_NAME),state);
//		MQTT_PublishQs0(P_TOPIC_NAME, json_str, strlen(json_str));
//		input_hold.ch4 = 0;
//	}
//	else if(input_hold.ch5)
//	{
//		static u8 state = 0;
//		state = !state;
//		sprintf(json_str,"{\"params\": {\"%s\": %u}}",STRI(DIN5_NAME),state);
//		MQTT_PublishQs0(P_TOPIC_NAME, json_str, strlen(json_str));
//		input_hold.ch5 = 0;
//	}
}

//{func} 数据上报
void APP_AliyunReport(void)
{
	APP_InputChenalAction_Process();
}
//指纹模块操作功能处理函数
void APP_FingerPrintOperate_Process(void)
{

//	else if(input_hold.ch3 || app_flags.identify_fingerprint_f)
//	{
//		u8 is_ok = 0;
//		printf("请按下手指，开始进行指纹识别 \r\n");
//		AM_BuildStatuesText("按下手指,进行指纹识别",result_buff);
//		//@ 添加数据，发布给服务器
//		MQTT_PublishQs0(P_TOPIC_NAME, (char *)result_buff, strlen((char *)result_buff)); 
//		sys.run_flags.led2_toggle_f = LED2_TOGG_SLOW;
//		is_ok = FP_MatchFingerPrint();
//		
//		if (is_ok == 0)
//		{
//			printf("指纹识别成功!!! \r\n\r\n");
//			AM_BuildStatuesText("指纹识别成功",result_buff);
//			//@ 添加数据，发布给服务器
//			MQTT_PublishQs0(P_TOPIC_NAME, (char *)result_buff, strlen((char *)result_buff)); 
//		}
//		else
//		{
//			printf("指纹识别失败!!! \r\n\r\n");
//			AM_BuildStatuesText("指纹识别失败",result_buff);
//			//@ 添加数据，发布给服务器
//			MQTT_PublishQs0(P_TOPIC_NAME, (char *)result_buff, strlen((char *)result_buff)); 
//		}
//		app_flags.identify_fingerprint_f = 0;
//		sys.run_flags.led2_toggle_f = LED2_TOGG_COMM;
//		input_hold.ch3 = 0;
//	}
}

//识别指纹功能处理函数
void APP_FingerPrintMattch_Process(void)
{

	
}

void APP_MQTT_Process(void)
{

	//	while (1)
	{
		/*--------------------------------------------------------------------*/
		/*      Connect_flag=0同服务器断开了连接,我们要重启连接服务器         */
		/*--------------------------------------------------------------------*/
		if (Connect_flag == 0)
		{
			printf("需要连接服务器\r\n"); //串口输出信息
			__HAL_TIM_DISABLE(&htim4);
			__HAL_TIM_DISABLE(&htim6);
			AIR720_RxCounter = 0;						  //WiFi接收数据量变量清零
			memset(AIR720_RX_BUF, 0, AIR720_RXBUFF_SIZE); //清空WiFi接收缓冲区
			u8 isok = NET_Conn_TCP_Server((u8 *)ServerIP, ServerPort);
			if (isok == 0)
			{												  //如果WiFi连接云服务器函数返回0，表示正确，进入if
				printf("建立TCP连接成功\r\n");				  			//串口输出信息
				Connect_flag = 1;							  							//Connect_flag置1，表示连接成功
				AIR720_RxCounter = 0;						  						//WiFi接收数据量变量清零
				memset(AIR720_RX_BUF, 0, AIR720_RXBUFF_SIZE); //清空WiFi接收缓冲区
				MQTT_Buff_Init();							  							//初始化发送缓冲区
			}
		}
		/*--------------------------------------------------------------------*/
		/*   Connect_flag=1同服务器建立了连接,我们可以发布数据和接收推送了    */
		/*--------------------------------------------------------------------*/
		else if (Connect_flag == 1)
		{
			/*-------------------------------------------------------------*/
			/*                     处理发送缓冲区数据                      */
			/*-------------------------------------------------------------*/
			if (MQTT_TxDataOutPtr != MQTT_TxDataInPtr)
			{ //if成立的话，说明发送缓冲区有数据了
				//3种情况可进入if
				//第1种：0x10 连接报文
				//第2种：0x82 订阅报文，且ConnectPack_flag置位，表示连接报文成功
				//第3种：SubcribePack_flag置位，说明连接和订阅均成功，其他报文可发
				if ((MQTT_TxDataOutPtr[2] == 0x10) || ((MQTT_TxDataOutPtr[2] == 0x82) && (ConnectPack_flag == 1)) || (SubcribePack_flag == 1))
				{
					printf("发送数据:0x%x\r\n", MQTT_TxDataOutPtr[2]); //串口提示信息
					MQTT_TxData((u8 *)MQTT_TxDataOutPtr);			   //发送数据
					MQTT_TxDataOutPtr += TBUFF_UNIT;				   //指针下移
					if (MQTT_TxDataOutPtr == MQTT_TxDataEndPtr)		   //如果指针到缓冲区尾部了
						MQTT_TxDataOutPtr = MQTT_TxDataBuf[0];		   //指针归位到缓冲区开头
				}
			} //处理发送缓冲区数据的else if分支结尾

			/*-------------------------------------------------------------*/
			/*                     处理接收缓冲区数据                      */
			/*-------------------------------------------------------------*/
			if (MQTT_RxDataOutPtr != MQTT_RxDataInPtr)
			{ //if成立的话，说明接收缓冲区有数据了
				printf("接收到数据:");
				/*-----------------------------------------------------*/
				/*                    处理CONNACK报文                  */
				/*-----------------------------------------------------*/
				//if判断，如果第一个字节是0x20，表示收到的是CONNACK报文
				//接着我们要判断第4个字节，看看CONNECT报文是否成功
				if (MQTT_RxDataOutPtr[2] == 0x20)
				{
					switch (MQTT_RxDataOutPtr[5])
					{
					case 0x00:
						printf("CONNECT报文成功\r\n"); //串口输出信息
						ConnectPack_flag = 1;		   //CONNECT报文成功，订阅报文可发
						break;						   //跳出分支case 0x00
					case 0x01:
						printf("连接已拒绝，不支持的协议版本，准备重启\r\n"); //串口输出信息
						Connect_flag = 0;									  //Connect_flag置零，重启连接
						break;												  //跳出分支case 0x01
					case 0x02:
						printf("连接已拒绝，不合格的客户端标识符，准备重启\r\n"); //串口输出信息
						Connect_flag = 0;										  //Connect_flag置零，重启连接
						break;													  //跳出分支case 0x02
					case 0x03:
						printf("连接已拒绝，服务端不可用，准备重启\r\n"); //串口输出信息
						Connect_flag = 0;								  //Connect_flag置零，重启连接
						break;											  //跳出分支case 0x03
					case 0x04:
						printf("连接已拒绝，无效的用户名或密码，准备重启\r\n"); //串口输出信息
						Connect_flag = 0;										//Connect_flag置零，重启连接
						break;													//跳出分支case 0x04
					case 0x05:
						printf("连接已拒绝，未授权，准备重启\r\n"); //串口输出信息
						Connect_flag = 0;							//Connect_flag置零，重启连接
						break;										//跳出分支case 0x05
					default:
						printf("连接已拒绝，未知状态，准备重启\r\n"); //串口输出信息
						Connect_flag = 0;							  //Connect_flag置零，重启连接
						break;										  //跳出分支case default
					}
				}
				//if判断，第一个字节是0x90，表示收到的是SUBACK报文
				//接着我们要判断订阅回复，看看是不是成功
				else if (MQTT_RxDataOutPtr[2] == 0x90)
				{
					switch (MQTT_RxDataOutPtr[6])
					{
					case 0x00:
					case 0x01:
						printf("订阅成功\r\n"); //串口输出信息
						SubcribePack_flag = 1;  //SubcribePack_flag置1，表示订阅报文成功，其他报文可发送
						Ping_flag = 0;			//Ping_flag清零
						TIM6_ENABLE_30S();		//启动30s的PING定时器
												//									LED1_State();                         //判断开关状态，并发布给服务器
						break;					//跳出分支
					default:
						printf("订阅失败，准备重启\r\n"); //串口输出信息
						Connect_flag = 0;				  //Connect_flag置零，重启连接
						break;							  //跳出分支
					}
				}
				//if判断，第一个字节是0xD0，表示收到的是PINGRESP报文
				else if (MQTT_RxDataOutPtr[2] == 0xD0)
				{
					printf("PING报文回复\r\n"); //串口输出信息
					if (Ping_flag == 1)
					{				   //如果Ping_flag=1，表示第一次发送
						Ping_flag = 0; //要清除Ping_flag标志
					}
					else if (Ping_flag > 1)
					{					   //如果Ping_flag>1，表示是多次发送了，而且是2s间隔的快速发送
						Ping_flag = 0;	 //要清除Ping_flag标志
						TIM6_ENABLE_30S(); //PING定时器重回30s的时间
					}
				}
				//if判断，如果第一个字节是0x30，表示收到的是服务器发来的推送数据
				//我们要提取控制命令
				else if ((MQTT_RxDataOutPtr[2] == 0x30))
				{
					printf("服务器等级0推送\r\n");			  //串口输出信息
					MQTT_DealPushdata_Qs0(MQTT_RxDataOutPtr); //处理等级0推送数据
				}
				else
				{
					printf("接收到错误数据 \r\n");
					u16 len = MQTT_RxDataOutPtr[0] * 256 + MQTT_RxDataOutPtr[1];
					for(int i=0;i<len;i++)
					{
						printf("%02x ",MQTT_RxDataOutPtr[i]);
					}
					printf("\r\n");
				}

				MQTT_RxDataOutPtr += RBUFF_UNIT;			//指针下移
				if (MQTT_RxDataOutPtr == MQTT_RxDataEndPtr) //如果指针到缓冲区尾部了
					MQTT_RxDataOutPtr = MQTT_RxDataBuf[0];  //指针归位到缓冲区开头
			}												//处理接收缓冲区数据的else if分支结尾

			/*-------------------------------------------------------------*/
			/*                     处理命令缓冲区数据                      */
			/*-------------------------------------------------------------*/
			if (MQTT_CMDOutPtr != MQTT_CMDInPtr)
			{											   //if成立的话，说明命令缓冲区有数据了
				printf("命令:%s \r\n", &MQTT_CMDOutPtr[2]); //串口输出信息
				char * json_buff = (char *)&MQTT_CMDOutPtr[2];
				
				/*{"method":"thing.service.RegisterFingerprint","id":"2005450991","params":{},"version":"1.0.0"}*/
				char method[32];
				sscanf((char *)json_buff,"{\"method\":\"%[^\"]",method);
				//{if} 收到服务器属性设置消息
				if(strstr(method,"thing.service.property.set"))
				{	
					char params_str[64],key[32];
					int val;
					//@ get params string format is : params:{"xxx":x}
					sscanf(json_buff,"{%*[^,],%*[^,],%[^,],%*[^}]",params_str);
					//@ get key string
					sscanf(params_str,"%*[^:]:{\"%[^\"]",key);
					//@ get value 
					sscanf(params_str,"%*[^:]:{%*[^:]:%d}",&val);
					
					for(int i=0;i<DOUT_MAX_CH;i++)
					{
						if(strstr(key,(char *)dout_map[i].name))
						{
							//.. control hardware
							dout_map[i].val = val;
//							AM_RefreshOutputChannel();
//							AM_RefreshOutputCH(i + 1);
							
//							char * method = "thing.event.property.post";
//							char * id = "203302322";
//							char * version = "1.0.0";
//							//.. create json package string	
//							char params_str[32];
							char publish_str[128];
//							sprintf(params_str,"{\"%s\":%d}",key,val);
//							sprintf(publish_str,"{\"mothod\":%s,\"id\":%s,\"params\":%s,\"version\":%s}",method,id,params_str,version);
							
							sprintf(publish_str,"{\"params\":{\"%s\":%u}}",dout_map[i].name,dout_map[i].val);
							MQTT_PublishQs0(P_TOPIC_NAME, publish_str, strlen((char *)publish_str)); //添加数据，发布给服务器
						}
					}

				}
				//{else if} 收到服务器服务调用消息
				else
				{
					//{"method":"thing.service.RegisterFingerprint","id":"1997931095","params":{},"version":"1.0.0"}
					char server_func[32];
					sscanf(method,"thing.service.%s",server_func);
					//{for} 查找出符合要求的函数
					for(int i=0;i<SERVER_FUNCTION_ITEM;i++)
					{
						char * is_ok = strstr((char *)server_funcs[i].name,server_func);
						if(is_ok)
						{
							//@ 动态调用处理函数
							printf("执行云端下发命令 \r\n");
							server_funcs[i].p_func();
						}
					}
				}	
//				memset(MQTT_CMDBuf,0,C_NUM * CBUFF_UNIT);
				MQTT_CMDOutPtr += CBUFF_UNIT;		  //指针下移
				if (MQTT_CMDOutPtr == MQTT_CMDEndPtr) //如果指针到缓冲区尾部了
					MQTT_CMDOutPtr = MQTT_CMDBuf[0];  //指针归位到缓冲区开头
			}										  //处理命令缓冲区数据的else if分支结尾
													  //Connect_flag=1的if分支的结尾
		}
	}
}

void APP_ProcessPOOL(void)
{
	APP_MQTT_Process();
	APP_InputChenalAction_Process();
	APP_FingerPrintOperate_Process();

//	if (sys.run_flags.fingerprint_match_f)
//	{
//		APP_FingerPrintMattch_Process();
//		sys.fingerprint_touch_f = 0;
//		sys.run_flags.fingerprint_match_f = 0;
//	}
	if(sys.run_flags.led1_toggle_f)
	{
		LED_ToggleLed(LED1);
		sys.run_flags.led1_toggle_f = 0;
	}
}

/*-------------------------------------------------*/
/*函数名：判断开关1状态，并发布给服务器            */
/*参  数：无                                       */
/*返回值：无                                       */
/*-------------------------------------------------*/
void LED1_State(void)
{
	char temp[TBUFF_UNIT]; //定义一个临时缓冲区
	//@ 如果LED1是高电平，说明是熄灭状态，需要回复关闭状态给服务器
	if (!READ_OUT1())
	{
		json_t *root;
		char *out;
		root = json_pack("{s:i}", "digital_output1", 1);
		root = json_pack("{s:s,s:s,s:o,s:s}", "method", "thing.event.property.post", "id", "203302322", "params", root, "version", "1.0.0");
		out = json_dumps(root, JSON_ENCODE_ANY);
		//		printf("out:%s\r\n", out);
		free(root);
		free(out);
	}
	else
	{
		json_t *root;
		char *out;
		root = json_pack("{s:i}", "digital_output1", 0);
		root = json_pack("{s:s,s:s,s:o,s:s}", "method", "thing.event.property.post", "id", "203302322", "params", root, "version", "1.0.0");
		out = json_dumps(root, JSON_ENCODE_ANY);
		//		printf("out:%s\r\n", out);
		free(root);
		free(out);
	}
	//@ 如果LED1是低电平，说明是点亮状态，需要回复打开状态给服务器
	//		sprintf(temp,"{\"method\":\"thing.event.property.post\",\"id\":\"203302322\",\"params\":{\"digital_output1\":1},\"version\":\"1.0.0\"}");
	MQTT_PublishQs0(P_TOPIC_NAME, temp, strlen(temp)); //添加数据，发布给服务器
}

void * ExtractVal(char * str, int num, char * type) {
	static char ret_c;
	static int ret_d;
	static float ret_f;
	static double ret_lf;

	void * ret_val;

	char temp_str[32], ret_str[32];
	memset(temp_str, 0, sizeof(temp_str));
	memset(ret_str, 0, sizeof(ret_str));
	char * cur_pos = strchr(str, ',');
	for (int i = 0; i < num; i++) {
		cur_pos++;
		char * end_pos = strchr(cur_pos, ',');
		memcpy(temp_str, cur_pos, end_pos - cur_pos);
//		printf("%s ",temp_str);
		if (i == num - 1) {
//			printf("%s ",temp_str);
			memcpy(ret_str, temp_str, strlen(temp_str));
		}

		memset(temp_str, 0, sizeof(temp_str));
		cur_pos = end_pos;
	}

	if (strcmp(type, "c") == 0) {
		ret_c = *ret_str;
		ret_val = &ret_c;
	} else if (strcmp(type, "d") == 0) {

	} else if (strcmp(type, "lf") == 0) {
		ret_lf = atof(ret_str);
		ret_val = &ret_lf;
	}
	return ret_val;
}
